﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Prob_Distributions_ClassLibrary;
using System.Windows.Forms;
using System.Drawing;

namespace colas
{
    class Colas
    {
        public DateTime desde { get; set; }
        public DateTime hasta { get; set; }
        public double media{ get; set; }
        public double desvEstandar { get; set; }
        public double tCompraTicket { get; set; }
        public double tEntregaPedido { get; set; }
        public double tConsumicionPedido { get; set; }
        public double tAdicionalesConsumicion{ get; set; }
        public double tUtilizacionMesa{ get; set; }
        public double tAdicionalesUtilizacion { get; set; }
        public double H { get; set; }
        public double K { get; set; }
        public double tiempo_espera_paquete_chico { get; set; }
        public double tiempo_espera_paquete_grande { get; set; }
        private int nroLinea = -1;
        gridline linea;

        //public List<linea_Euler> lineas_euler_chico;
        //public List<linea_Euler> lineas_euler_grande;


        public System.Windows.Forms.DataGridView DgColas { get; set; } //grilla de pantalla para cargar              
        private Eleccion eleccion = new Eleccion();
               
        

        public Colas(String desde, String hasta, String media, String desvEstandar, String tCompraTicket, String tEntregaPedido, String tConsumicionPedido, String tAdicionalesConsumicion, String tUtilizacionMesa, String tAdicionalesUtilizacion, String H, String K, DataGridView dgColas)
        {
                     
            //Modificado ya que da error en los distintos formatos (MG)
            this.desde = DateTime.Parse(desde);
            this.hasta = DateTime.Parse(hasta);


            this.media = double.Parse(media); ;
            this.desvEstandar = double.Parse(desvEstandar);
            this.tCompraTicket = double.Parse(tCompraTicket);
            this.tEntregaPedido = double.Parse(tEntregaPedido);
            this.tConsumicionPedido = double.Parse(tConsumicionPedido)*60;
            this.tAdicionalesConsumicion=double.Parse(tAdicionalesConsumicion)*60;
            this.tUtilizacionMesa = double.Parse(tUtilizacionMesa)*60;
            this.tAdicionalesUtilizacion = double.Parse(tAdicionalesUtilizacion)*60;
            this.K = double.Parse(K);
            this.H = double.Parse(H);
            this.DgColas= dgColas;            
        }                           
   

        private void cargarLinea(gridline line, int i)
        {
            i -= 1;            
            DgColas.Rows.Add();
            DgColas["Reloj", i].Value = line.Reloj < 0 ? "0" : line.Reloj.ToString();//new DateTime().AddSeconds(line.Reloj).ToLongTimeString();
            DgColas["Reloj", i].Value = new DateTime().AddSeconds(line.Reloj).ToLongTimeString();
            DgColas["evento", i].Value = Enum.GetName(typeof(Utils.eventos), line.evento);
            DgColas["rnd_llegada", i].Value = line.rnd_llegada < 0 ? "-" : line.rnd_llegada.ToString();
            DgColas["rndn_llegada", i].Value = line.rndn_llegada < 0 ? "-" : line.rndn_llegada.ToString();
            DgColas["proxima_llegada_cliente", i].Value = line.proxima_llegada_cliente < 0 ? "-" : line.proxima_llegada_cliente.ToString();
            DgColas["rnd_eleccion", i].Value = line.rnd_eleccion< 0 ? "-" : line.rnd_eleccion.ToString();
            DgColas["eleccion", i].Value = Enum.GetName(typeof(Utils.eleccion), line.eleccion);
            DgColas["fin_ticket", i].Value = line.fin_ticket< 0 ? "-" : line.fin_ticket.ToString();
            DgColas["estado_cajero", i].Value = Enum.GetName(typeof(Utils.cajero), line.estado_cajero);
            DgColas["cola_cajero", i].Value = line.cola_cajero< 0 ? "0" : line.cola_cajero.ToString();
            DgColas["cola_entrega", i].Value = line.cola_entrega< 0 ? "0" : line.cola_entrega.ToString();
            DgColas["rnd_entrega1", i].Value = line.rnd_entrega1< 0 ? "-" : line.rnd_entrega1.ToString();
            DgColas["rnde_entrega1", i].Value = line.rnde_entrega1< 0 ? "-" : line.rnde_entrega1.ToString();
            DgColas["fin_entrega1", i].Value = line.fin_entrega1< 0 ? "-" : line.fin_entrega1.ToString();
            DgColas["estado_empleado1", i].Value = Enum.GetName(typeof(Utils.empleado), line.estado_empleado1);
            DgColas["rnd_entrega2", i].Value = line.rnd_entrega2< 0 ? "-" : line.rnd_entrega2.ToString();
            DgColas["rnde_entrega2", i].Value = line.rnde_entrega2< 0 ? "-" : line.rnde_entrega2.ToString();
            DgColas["fin_entrega2", i].Value = line.fin_entrega2< 0 ? "-" : line.fin_entrega2.ToString();
            DgColas["estado_empleado2", i].Value = Enum.GetName(typeof(Utils.empleado), line.estado_empleado2);
            DgColas["rnd_eleccion_consumir", i].Value = line.rnd_eleccion_consumir < 0 ? "-" : line.rnd_eleccion_consumir.ToString();
            DgColas["eleccion_consumir", i].Value = line.eleccion_consumir < 0 ? "-" : Enum.GetName(typeof(Utils.eleccion_consumir), line.eleccion_consumir);

            DgColas["contador_personas", i].Value = line.contador_personas< 0 ? "0" : line.contador_personas.ToString();
            DgColas["acumulador_permanencia", i].Value = line.acumulador_permanencia < 0 ? "0" : new DateTime().AddSeconds(line.acumulador_permanencia).ToString("HH:mm:ss");

            if (gridline.clientes.Count > 0 && gridline.clientes.Count > (DgColas.Columns.Count - 23) / 8 && DgColas.Columns.Count < 600) //
            {
                DgColas.Columns.Add("estado_cliente" + (gridline.clientes.Count - 1), "Estado Cliente " + gridline.clientes.Count);
                DgColas.Columns.Add("desde_cliente" + (gridline.clientes.Count - 1), "Hora Inicio C" + gridline.clientes.Count);
                DgColas.Columns.Add("rnd_cliente" + (gridline.clientes.Count - 1), "RND C" + gridline.clientes.Count);         

                DgColas.Columns.Add("hasta_cliente" + (gridline.clientes.Count - 1), "Hora Fin C" + gridline.clientes.Count);
                DgColas.Columns.Add("tamanio_pedido" + (gridline.clientes.Count - 1), "Tamaño Pedido" + gridline.clientes.Count);
                //if (line.eleccion == (int)Utils.eleccion.COMPRA)
                {
                    DgColas.Columns.Add("fin_consumicion" + (gridline.clientes.Count - 1), "Fin Consumición" + gridline.clientes.Count); 
                }

                //if (line.eleccion == (int)Utils.eleccion.SE_SIENTA)
                {
                    DgColas.Columns.Add("fin_uso_mesa" + (gridline.clientes.Count - 1), "Fin Uso Mesa" + gridline.clientes.Count);
                }

                //if (line.eleccion == (int)Utils.eleccion.DE_PASO)
                {
                    DgColas.Columns.Add("fin_paso" + (gridline.clientes.Count - 1), "Fin Paso" + gridline.clientes.Count); 
                }                                                                               
            }
            for (int j = 0; j < gridline.clientes.Count && DgColas.Columns.Count < 600; j++) //
            { 

                Cliente cli=gridline.clientes[j];
                DgColas["estado_cliente" + j, i].Value = Enum.GetName(typeof(Utils.cliente), cli.estado);
                DgColas["desde_cliente" + j, i].Value = new DateTime().AddSeconds(cli.horaEntrada).ToString("HH:mm:ss");

                DgColas["hasta_cliente" + j, i].Value = (cli.horaSalida>0?new DateTime().AddSeconds(cli.horaSalida).ToString("HH:mm:ss"): "-");                
                DgColas["rnd_cliente" + j, i].Value = cli.rndCliente <= 0 ? "-" : cli.rndCliente.ToString();
                DgColas["tamanio_pedido" + j, i].Value = Enum.GetName(typeof(Utils.eleccion_tamanio), cli.tamanio);
                //if (DgColas.Columns["fin_consumicion" + j] != null)
                {
                    DgColas["fin_consumicion" + j, i].Value = cli.finComsumicion <= 0 ? "-" : cli.finComsumicion.ToString();
                }
                //if (DgColas.Columns["fin_uso_mesa" + j] != null)
                {
                    DgColas["fin_uso_mesa" + j, i].Value = cli.finUsoMesa <= 0 ? "-" : cli.finUsoMesa.ToString();
                }
                //if (DgColas.Columns["fin_paso" + j] != null)
                {
                    DgColas["fin_paso" + j, i].Value = cli.finPaso <= 0 ? "-" : cli.finPaso.ToString();
                }


            }
            double celdaAPintar = double.MaxValue;
            int posicion = 0;
            for (int j = 0; j < DgColas.Columns.Count; j++)
            {

                DataGridViewTextBoxCell celda = (DataGridViewTextBoxCell) DgColas.Rows[i].Cells[j];
                String nombreColumna=DgColas.Columns[j].Name;
                string valor = (string)celda.Value;
                if (valor != null)
                {
                    double result;
                    bool columnaValida = false;
                    if (nombreColumna.IndexOf("fin") != -1 || nombreColumna.IndexOf("proxima") != -1)
                    {
                        columnaValida = true;
                        DgColas[j, i].Style.ForeColor = Color.Black;
                        DgColas[j, i].Style.BackColor = Color.LightGray;
                       
                    }
                    else
                    {
                        columnaValida = false;
                    }
                    if (double.TryParse(valor, out result))
                    {                          
                        if (result > 0 && result < celdaAPintar && columnaValida)
                        {
                            celdaAPintar = result;                            
                            posicion = j;
                        }
                        if (columnaValida)
                        {
                            DgColas[nombreColumna, i].Value = new DateTime().AddSeconds(result).ToLongTimeString();
                        }
                    }                    
                }                
            }
            DgColas[posicion, i].Style.ForeColor = Color.Red;
            DgColas[posicion, i].Style.BackColor = Color.Black;
        }

        internal double  generarSimulacion()
        {
                linea = new gridline();
                DgColas.Rows.Clear();
            //Cargo linea inicial
                linea.Reloj = desde.TimeOfDay.TotalSeconds;
                linea.evento = -1;
                Random rndinicial = new Random();
                linea.rnd_llegada = -1;
                double suma=0;
                //Calculo llegada cliente con distribución Normal 
                //por convolución
                for (int i = 0; i < 12; i++) { suma += rndinicial.NextDouble(); }
                linea.rndn_llegada = (suma-6)*this.desvEstandar+this.media;
                linea.proxima_llegada_cliente = linea.Reloj + linea.rndn_llegada;
                cargarLinea(linea, 1);
            ////////////FIN CARGA PRIMERA LINEA///////////////////////////////
                DateTime reloj = this.desde;
                int tipoEvento = 0;
                IEvento evento = null;
                nroLinea = 1;
                while (reloj.CompareTo(this.hasta) < 0 )
                {
                    nroLinea++;                    
                    tipoEvento = linea.getTipoProximoEvento();
                    switch (tipoEvento)
                    {
                        case (int)Utils.eventos.LLEGADA_CLIENTE: evento = new EventoLlegadaCliente(this.media,this.desvEstandar, this.tCompraTicket, this.tUtilizacionMesa, this.tAdicionalesUtilizacion); break;                        
                        case (int)Utils.eventos.FIN_COMPRA_TICKET: evento = new EventoFinCompraTicket(this.tCompraTicket, this.tEntregaPedido); break;
                        case (int)Utils.eventos.FIN_CONSUMICION_PEDIDO: evento = new EventoFinConsumicion(); break;
                        case (int)Utils.eventos.FIN_ENTREGA_1: evento = new EventoFinEntregaPedido(1, tConsumicionPedido,tAdicionalesConsumicion, tEntregaPedido, tiempo_espera_paquete_chico, tiempo_espera_paquete_grande); break;
                        case (int)Utils.eventos.FIN_ENTREGA_2: evento = new EventoFinEntregaPedido(2, tConsumicionPedido, tAdicionalesConsumicion, tEntregaPedido, tiempo_espera_paquete_chico, tiempo_espera_paquete_grande); break;
                        case (int)Utils.eventos.FIN_PASO: evento = new EventoFinPaso(); break;
                        case (int)Utils.eventos.FIN_UTILIZACION_MESA: evento = new EventoFinOcupacionMesa(); break; 
                       
                    }
                    linea = evento.llenarLinea(linea);
                    cargarLinea(linea, nroLinea);
                    reloj = DateTime.Today.AddSeconds(linea.Reloj);
                }   
            return linea.acumulador_permanencia / linea.contador_personas;    
        }

        public void proximaLinea()
        {
            if (nroLinea < 0)
            {
                //cargo primera línea
                linea = new gridline();
                DgColas.Rows.Clear();
                //Cargo linea inicial
                linea.Reloj = desde.TimeOfDay.TotalSeconds;
                linea.evento = -1;
                Random rndinicial = new Random();
                linea.rnd_llegada = -1;
                double suma = 0;
                //Calculo llegada cliente con distribución Normal 
                //por convolución
                for (int i = 0; i < 12; i++) { suma += rndinicial.NextDouble(); }
                linea.rndn_llegada = (suma - 6) * this.desvEstandar + this.media;
                linea.proxima_llegada_cliente = linea.Reloj + linea.rndn_llegada;
                cargarLinea(linea, 1);
                nroLinea = 1;
            }
            else
            {
                DateTime reloj = this.desde;
                int tipoEvento = 0;
                IEvento evento = null;
                
                if (reloj.CompareTo(this.hasta) < 0 && nroLinea < 100)
                {
                    nroLinea++;
                    tipoEvento = linea.getTipoProximoEvento();
                    switch (tipoEvento)
                    {
                        case (int)Utils.eventos.LLEGADA_CLIENTE: evento = new EventoLlegadaCliente(this.media, this.desvEstandar, this.tCompraTicket, this.tUtilizacionMesa, this.tAdicionalesUtilizacion); break;
                        case (int)Utils.eventos.FIN_COMPRA_TICKET: evento = new EventoFinCompraTicket(this.tCompraTicket, this.tEntregaPedido); break;
                        case (int)Utils.eventos.FIN_CONSUMICION_PEDIDO: evento = new EventoFinConsumicion(); break;
                        case (int)Utils.eventos.FIN_ENTREGA_1: evento = new EventoFinEntregaPedido(1, tConsumicionPedido, tAdicionalesConsumicion, tEntregaPedido, tiempo_espera_paquete_chico, tiempo_espera_paquete_grande); break;
                        case (int)Utils.eventos.FIN_ENTREGA_2: evento = new EventoFinEntregaPedido(2, tConsumicionPedido, tAdicionalesConsumicion, tEntregaPedido, tiempo_espera_paquete_chico, tiempo_espera_paquete_grande); break;
                        case (int)Utils.eventos.FIN_PASO: evento = new EventoFinPaso(); break;
                        case (int)Utils.eventos.FIN_UTILIZACION_MESA: evento = new EventoFinOcupacionMesa(); break;

                    }
                    linea = evento.llenarLinea(linea);
                    cargarLinea(linea, nroLinea);
                    reloj = DateTime.Today.AddSeconds(linea.Reloj);
                }            
 
            }
        }

        public void calcularTiemposEspera()
        {
            List<linea_Euler> lineas_euler_chico = new List<linea_Euler>();
            List<linea_Euler> lineas_euler_grande = new List<linea_Euler>();
            Euler _euler = new Euler(K, H);
            tiempo_espera_paquete_chico = _euler.calcular_tiempo_pedido((int)Utils.eleccion_tamanio.CHICO,  lineas_euler_chico);
            tiempo_espera_paquete_grande = _euler.calcular_tiempo_pedido((int)Utils.eleccion_tamanio.GRANDE, lineas_euler_grande);
            //Mostrar datos en grilla
            Tablas_Euler tablas_euler_1 = new Tablas_Euler();
            System.Windows.Forms.DataGridView dgc;
            System.Windows.Forms.DataGridView dgg;
            dgc = new System.Windows.Forms.DataGridView();
            dgg = new System.Windows.Forms.DataGridView();
            dgc.DataSource=lineas_euler_chico;
            dgg.DataSource=lineas_euler_grande;
            tablas_euler_1.set_euler(dgc, dgg);
            tablas_euler_1.Show();

        }
    }
}
    